// LeetCode 主站 Problem Nr. 147: 对链表进行插入排序

/*
给定单个链表的头 head ，使用 插入排序 对链表进行排序，并返回 排序后链表的头 。

插入排序 算法的步骤:
    插入排序是迭代的，每次只移动一个元素，直到所有元素可以形成一个有序的输出列表。
    每次迭代中，插入排序只从输入数据中移除一个待排序的元素，找到它在序列中适当的位置，并将其插入。
    重复直到所有输入数据插入完为止。

下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。
每次迭代时，从输入数据中删除一个元素(红色)，并就地插入已排序的列表中。

对链表进行插入排序。

示例 1：
	输入: head = [4,2,1,3]
	输出: [1,2,3,4]

示例 2：
	输入: head = [-1,5,3,4,0]
	输出: [-1,0,3,4,5]

提示：
    列表中的节点数在 [1, 5000]范围内
    -5000 <= Node.val <= 5000

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/insertion-sort-list
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
*/

package main

import "github.com/saint-yellow/think-leetcode/ds"

type ListNode = ds.SinglyLinkedNode[int]

func insertionSortList(head *ListNode) *ListNode {
	return method1(head)
}

func method1(head *ListNode) *ListNode {
	// 考虑空链表传入的情况
	// if head == nil {
	// 	return head
	// }

	nodes := make([]*ListNode, 0)
	current := head
	for current != nil {
		next := current.Next
		current.Next = nil
		nodes = append(nodes, current)
		current = next
	}

	// insertion sort...
	for i := 1; i < len(nodes); i++ {
		position := i
		tempNode := nodes[position]
		for position > 0 && nodes[position-1].Val > tempNode.Val {
			nodes[position] = nodes[position-1]
			position -= 1
		}
		nodes[position] = tempNode
	}

	for i := 0; i < len(nodes) - 1; i++ {
		nodes[i].Next = nodes[i+1].Next
	}

	return nodes[0]
}

func method2(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}

	sentinel := &ListNode{
		Val: -1,
		Next: head,
	}

	sorted, current := head, head.Next
	for current != nil {
		if sorted.Val <= current.Val {
			sorted = sorted.Next
		} else {
			previous := sentinel
			for previous.Next.Val <= current.Val {
				previous = previous.Next
			}

			sorted.Next = current.Next
			current.Next = previous.Next
			previous.Next = current
		}
		current = sorted.Next
	}
	return sentinel.Next
}
